use js_sys::*;
use wasm_bindgen::prelude::*;
use serde::{Serialize, Deserialize};
use std::collections::HashMap;

use web_sys::{ErrorEvent, MessageEvent, WebSocket};

macro_rules! console_log {
    ($($t:tt)*) => (log(&format_args!($($t)*).to_string()))
}

#[derive(Serialize, Deserialize, Debug)]
pub struct Example {
    pub field1: HashMap<u32, String>,
    pub field2: Vec<Vec<f32>>,
    pub field3: [f32; 4],
}

#[wasm_bindgen(js_namespace = worker_api)]
extern "C" {
    fn name()-> String;
}

#[wasm_bindgen]
extern "C" {
    #[wasm_bindgen(js_namespace = console)]
    fn log(s: &str);

}

#[wasm_bindgen]
pub fn greet(n: &str) -> JsValue{
 
    log(&format!("I am a worker, {} : {}!", &name(), n));

    let mut field1 = HashMap::new();
    field1.insert(0, String::from("ex"));

    let example = Example {
        field1,
        field2: vec![vec![1., 2.], vec![3., 4.]],
        field3: [1., 2., 3., 4.]
    };
   
    serde_wasm_bindgen::to_value(&example).unwrap()
}

#[derive(PartialEq)]
pub enum GameState {
    Player1Move,
    Player2Move,
    Player1Win,
    Player2Win,
    Draw
}

#[wasm_bindgen]
pub struct ChineseCheckers{
    board: [[i8;17];17],
    selected: [i32;2], // the current marble being moved
    game_state: GameState, // 1: player1's move, 2: player2's move, 3: player1 wins, 4: player2 wins, 5: draw
    depth: i32,
    value: i16,
    result: [bool;2]
}

#[wasm_bindgen]
impl ChineseCheckers{
    #[wasm_bindgen(constructor)]
    pub fn new() -> ChineseCheckers{

        let mut board = [[0;17];17];

        for i in 0..=16usize {
            for j in 0..=16usize {
                if (i+j)%2 == 1 && ((i-8) as i16).abs() + ((j-8) as i16).abs() > 8{
                    board[i][j] = -1;
                }else if i < 4 {
                    board[i][j] = 1;
                }else if i > 12  {
                    board[i][j] = 2;
                }
            }
        }
        

        ChineseCheckers { 
            board: [[0;17];17],
            selected: [0;2],
            game_state: GameState::Player2Move,
            depth: 2,
            value: 120,
            result:[false;2]
        }
    }

    pub fn increase_depth(&mut self){
        self.depth = self.depth + 2;
        if self.depth == 8 {
            self.depth = 2;
        }
    }

    pub fn clickable(&self)->bool{
        if self.game_state != GameState::Player2Move
        {
            return  false;
        }
        return true;
    }

    pub fn score(&self)->i32{
    let mut player_status = Vec::new();

    let mut opponent_status = Vec::new();

    for i in 0..=16usize{
        for j in 0..16usize{
            if self.board[i][j] == 1 {
                player_status.push([i,j]);
            }
            if self.board[i][j] == 2 {
                opponent_status.push([i,j]);
            }
        }
    }

    let mut player_vertical_count = -20;
    let mut opponent_vertical_count = -20;
    let mut player_horizontal_count = 0;
    let mut opponent_horizontal_count = 0;

    for pos in player_status.iter(){
        player_vertical_count += pos[0] as i32;
        player_horizontal_count += ((pos[1] as i32 -8).abs()/2 -1).abs();
    }
    for pos in opponent_status.iter(){
        opponent_vertical_count += pos[0] as i32;
        opponent_horizontal_count += ((pos[1] as i32 -8).abs()/2 -1).abs();
    }

    player_vertical_count + opponent_vertical_count + (opponent_horizontal_count - player_horizontal_count)/2
      
    }

    pub fn check_end(&mut self){
        let mut result = [true;2];
        for i in 0..=16usize{
            for j in 0..=16usize{
                if i< 4 && self.board[i][j] != -1 && self.board[i][j] !=2{
                    result[1] = false;
                }
                if i>12 && self.board[i][j] != -1 && self.board[i][j] !=1{
                    result[0] = false;
                }
            }
        }
        self.result = result;
    }

   pub fn next_move(){

   }
}